package com.weilele.mvvm.base.helper

import android.app.Activity
import android.content.ContextWrapper
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.*
import androidx.viewbinding.ViewBinding
import com.weilele.mvvm.adapter.createViewBindingInstance
import com.weilele.mvvm.adapter.getParameterizedType
import com.weilele.mvvm.base.livedata.StatusData
import com.weilele.mvvm.utils.safeGet
import java.lang.NullPointerException

/**
 * 创建viewModel
 *
 */
@Deprecated(
    "不再推荐这种方式创建viewModel",
    replaceWith = ReplaceWith("by mvvmViewModel(owner: ViewModelStoreOwner)")
)
inline fun <reified T : ViewModel> ViewModelStoreOwner.createViewModel(): T {
    return ViewModelProvider(this).get(T::class.java)
}

/**
 * activity的viewModel
 */
@Deprecated(
    "不再推荐这种方式创建viewModel",
    replaceWith = ReplaceWith("by mvvmActivityViewModel()")
)
inline fun <reified T : ViewModel> Fragment.createActivityViewModel(): T {
    return activity?.createViewModel()
        ?: throw NullPointerException(
            if (activity == null) "activity is null"
            else "activity ViewModel not find ${T::class.java.simpleName}"
        )
}

/**
 * 父fragment的viewModel
 */
@Deprecated(
    "不再推荐这种方式创建viewModel",
    replaceWith = ReplaceWith("by mvvmViewModel(owner: ViewModelStoreOwner)")
)
inline fun <reified T : ViewModel> Fragment.createParentFragmentViewModel(): T {
    return parentFragment?.createViewModel()
        ?: throw NullPointerException(
            if (parentFragment == null) "parentFragment is null"
            else "parentFragment ViewModel not find ${T::class.java.simpleName}"
        )
}


fun <T> LifecycleOwner.observerLiveData(
    liveData: LiveData<T>,
    observer: Observer<T?>,
): Observer<T?> {
    liveData.observe(this, observer)
    return observer
}

inline fun <T> LifecycleOwner.observerLiveDataSuccess(
    liveData: LiveData<StatusData<T>>,
    crossinline call: (T) -> Unit
): Observer<StatusData<T>?> {
    val observer = Observer<StatusData<T>?> {
        val oldData = it?.data
        if (it?.status == StatusData.Success
            && oldData != null
        ) {
            call.invoke(oldData)
        }
    }
    liveData.observe(this, observer)
    return observer
}

fun <T> LiveData<T>.observeForeverLiveData(
    observer: Observer<T?>,
): Observer<T?> {
    this.observeForever(observer)
    return observer
}

inline fun <T> LiveData<StatusData<T>>.observerForeverLiveDataSuccess(
    crossinline call: (T) -> Unit
): Observer<StatusData<T>?> {
    val observer = Observer<StatusData<T>?> {
        val oldData = it?.data
        if (it?.status == StatusData.Success
            && oldData != null
        ) {
            call.invoke(oldData)
        }
    }
    this.observeForever(observer)
    return observer
}

/**
 * 在activity或者faragment创建Binding
 */
fun <Binding : ViewBinding?> Any.createViewBinding(
    inflater: LayoutInflater, cls: Class<Binding>? = null, parent: ViewGroup? = null,
    attach: Boolean = false, position: Int = 0
): Binding? {
    val type = cls ?: javaClass.getParameterizedType()
        ?.actualTypeArguments?.get(position)
    if (type == ViewBinding::class.java) {
        return null
    }
    return type.safeGet<Class<Binding>>()?.createViewBindingInstance(inflater, parent, attach)
}

fun BaseMvvmInterface.defaultMvvmCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {
    val beforeView = beforeMvvmCreateView(inflater, container, savedInstanceState)
    val realContainer = beforeView ?: container
    val createView = onMvvmCreateView(inflater, realContainer, savedInstanceState)
    return when (val afterView =
        afterMvvmCreateView(inflater, beforeView, createView, savedInstanceState)) {
        is Int -> {
            inflater.inflate(afterView, realContainer, false)
        }
        is View -> {
            afterView
        }
        is ViewBinding -> {
            afterView.root
        }
        null -> {
            //什么都不做
            null
        }
        else -> {
            throw IllegalArgumentException("getLayoutResOrView() only return view/LayoutRes")
        }
    }
}